# Baphomet-py (action RPG desenvolvido em Python)
# Desenvolvido por:
#   Guilherme Cardoso Soares
#   Raphael de Leon Ferreira Lupchinski
#
# https://code.google.com/p/baphomet-py/
# Lancado sobre GNU GPL v3

# modulos padroes
import random, sys, copy, os, pygame, functools

# modulos gerados
from Player import *
from Item  import *
from NPC  import *
from Position  import *

from pygame.locals import *

FPS = 30 # taxa de refresh da tela
WINWIDTH = 800 # largura da tela
WINHEIGHT = 600 # altura da tela
HALF_WINWIDTH = int(WINWIDTH / 2) # metade da largura da tela
HALF_WINHEIGHT = int(WINHEIGHT / 2) # metade da altura da tela

# definicao das propriedades do cenario
TILEWIDTH = 32
TILEHEIGHT = 32

CAM_MOVE_SPEED = 1 # por quantos pixels a camera anda

# definicao de propriedades dos personagens
CHARWIDTH = 32
CHARHEIGHT = 32

# definicao de algumas cores
BRIGHTBLUE = (  0, 170, 255)
WHITE      = (255, 255, 255)
RED        = (255,   0,   0)
GREEN      = (  0, 255,   0)
BLUE       = (  0,   0, 255)
BLACK      = (  0,   0,   0)
GRAY       = (127, 127, 127),
DARKGRAY   = ( 30,  30,  30)
BGCOLOR = DARKGRAY
TEXTCOLOR = WHITE

# algumas constantes
UP = 'up'
DOWN = 'down'
LEFT = 'left'
RIGHT = 'right'

def main():
    """Funcao principal do Baphomet.
    Faz a carga dos arquivos de imagem que serao usados,
    monta os dicionarios que contem tais arquivos,
    define as codificacoes do cenario e chama o loop principal."""
    global FPSCLOCK, DISPLAYSURF, IMAGESDICT, TILEMAPPING, BASICFONT, BASICFONTSMALL
    global PLAYER, ENEMIES, ITENS

    # inicializacao do Pygame
    pygame.init()
    FPSCLOCK = pygame.time.Clock()

    # Criacao da superficie onde o jogo sera desenhado.
    # Pygame utiliza Surfaces (SURF) para Blitar imagens e textos
    DISPLAYSURF = pygame.display.set_mode((WINWIDTH, WINHEIGHT))

    pygame.display.set_caption('Baphomet-py')
    BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
    BASICFONTSMALL = pygame.font.Font('freesansbold.ttf', 12)

    # Um dicionario global de todas as imagens que serao carregadas
    # pela funcao Load do Pygame.
    IMAGESDICT = {'cement': pygame.image.load('src/tileset/cement.png'),
                  'light-wood': pygame.image.load('src/tileset/light-wood.png'),
                  'dark-wood': pygame.image.load('src/tileset/dark-wood.png'),

                  'title': pygame.image.load('src/pictures/title.png'),
                  'solved': pygame.image.load('src/pictures/solved.png'),
                  'gameover': pygame.image.load('src/pictures/gameover.png'),

                  'mainup': pygame.image.load('src/charset/mainup.png'),
                  'maindown': pygame.image.load('src/charset/maindown.png'),
                  'mainleft': pygame.image.load('src/charset/mainleft.png'),
                  'mainright': pygame.image.load('src/charset/mainright.png'),
                  'mainupattacking': pygame.image.load('src/charset/mainupattacking.png'),
                  'maindownattacking': pygame.image.load('src/charset/maindownattacking.png'),
                  'mainleftattacking': pygame.image.load('src/charset/mainleftattacking.png'),
                  'mainrightattacking': pygame.image.load('src/charset/mainrightattacking.png'),
                  'slime': pygame.image.load('src/charset/slime.png'),
                  'bat': pygame.image.load('src/charset/bat.png'),
                  'zombie': pygame.image.load('src/charset/zombie.png'),
                  'skeleton': pygame.image.load('src/charset/skeleton.png'),

                  'accessory': pygame.image.load('src/icon/accessory.png'),
                  'armor': pygame.image.load('src/icon/armor.png'),
                  'blueshield': pygame.image.load('src/icon/blueshield.png'),
                  'shield': pygame.image.load('src/icon/shield.png'),
                  'sword': pygame.image.load('src/icon/sword.png'),
                  'yellowarmor': pygame.image.load('src/icon/yellowarmor.png'),
                  }

    # Um dicionario global que codifica o mapa em txt para a surface
    TILEMAPPING = {'x': IMAGESDICT['dark-wood'],
                   '#': IMAGESDICT['light-wood'],
                   ' ': IMAGESDICT['cement']}

    # Um objeto da classe Player para representar o jogador
    PLAYER = Player('Quevedo',1,30,30,7,7,2,3,0.8,
                    IMAGESDICT['maindown'],2,False,1,1,0,0,DOWN,0,0,
                    False,False,False,False,None,None,
                    None,None,2,3,0.8,[])

    # Um dicionario de inimigos instanciados da classe NPC
    ENEMIES = {'1': NPC("Slime",1,5,5,2,2,3,2,0.2,IMAGESDICT['slime'],1,False,1,1,1,0,0,DOWN),
               '2': NPC("Bat",2,7,7,1,1,5,3,0.4,IMAGESDICT['bat'],2,False,1,1,2,0,0,DOWN),
               '3': NPC("Zombie",3,10,10,3,3,10,5,0.2,IMAGESDICT['zombie'],2,False,1,1,3,0,0,DOWN),
               '4': NPC("Skeleton",4,13,13,5,5,15,6,0.6,IMAGESDICT['skeleton'],3,False,1,1,4,0,0,DOWN)}

    # Um dicionarios dos itens estanciados da classe Item
    ITENS = {'a': Item("Sword",12.5,IMAGESDICT['sword'],3,0,0.2,1,0,0),
             'b': Item("Yellow Shield",18.5,IMAGESDICT['shield'],0,2,0.0,2,0,0),
             'c': Item("Blue Shield",25.0,IMAGESDICT['blueshield'],0,3,0.1,3,0,0),
             'd': Item("Black Armor",30.0,IMAGESDICT['armor'],0,4,0.1,4,0,0),
             'e': Item("Yellow Armor",50.0,IMAGESDICT['yellowarmor'],0,4,0.2,5,0,0),
             'f': Item("Cord Ring",35.0,IMAGESDICT['accessory'],0,0,0.3,6,0,0)}

    startScreen() # show the title screen until the user presses a key

    # Faz a leitura do cenario onde o jogo ira se passar
    level = readLevelFile('src/map.txt')

    # Roda a fase carregada do txt para comecar o jogo
    while True:
        result = runLevel(level)

        if result in ('solved', 'gameover'):
            terminate()
            break

        if result == 'reset': # reinicia a fase
            level = readLevelFile('src/map.txt')


def startScreen():
    """Mostra a tela Inicial do jogo e fica na mesma ate 
    que uma tecla seja pressionada."""

    # Posicao da imagem de titulo
    titleRect = IMAGESDICT['title'].get_rect()
    topCoord = 50 # topCoord guarda a posicao do topo do retangulo
    titleRect.top = topCoord
    titleRect.centerx = HALF_WINWIDTH
    topCoord += titleRect.height

    # Guarda a lista de intrucoes que sao mostradas na tela inicial
    Instrucoes = ['Mate os inimigos no cenario.',
                 ' ',
                 'AWSD - movem o personagem pelo cenario.',
                 'K - ataca.',
                 'E - interage com objetos no cenario.',
                 'BACKSPACE - reinicia a missao.',
                 'ESC sai do jogo.',]

    # Comeca desenhando uma tela vazia de cor BGCOLOR
    DISPLAYSURF.fill(BGCOLOR)

    # Desenha a imagem de titulo
    DISPLAYSURF.blit(IMAGESDICT['title'], titleRect)

    # Escreve as instrucoes
    maxLen = len(Instrucoes[0])
    for i in range(len(Instrucoes)):
        if len(Instrucoes[i]) > maxLen:
            maxLen = len(Instrucoes[i])

    topCoord += 30
    for i in range(len(Instrucoes)):
        instSurf = BASICFONTSMALL.render(Instrucoes[i], 1, TEXTCOLOR)
        instRect = instSurf.get_rect()
        topCoord += 10 # 10 pixelsentre cada linha
        instRect.top = topCoord
        instRect.left = HALF_WINWIDTH/2 - maxLen/2
        topCoord += instRect.height # Adjust for the height of the line.
        DISPLAYSURF.blit(instSurf, instRect)

    while True: # Main loop for the start screen.
        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()
            elif event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    terminate()
                return # user has pressed a key, so return.

        # Display the DISPLAYSURF contents to the actual screen.
        pygame.display.update()
        FPSCLOCK.tick()


def readLevelFile(filename):
    """Faz a leitura do mapa criado em map.txt (ou qualquer outro)
    e gera uma variavel level que sera usada para a montagem
    do cenario (com surfaces e blits)"""

    assert os.path.exists(filename), 'Nao consio abrir o arquivo: %s' % (filename)
    mapFile = open(filename, 'r')
    # A fase deve conter uma linha em branco no final
    content = mapFile.readlines() + ['\r\n'] 
    mapFile.close()

    mapTextLines = [] # contem as linhas do mapa
    mapObj = [] # o mapa gerado de mapTextLines
    for lineNum in range(len(content)): # Para cada linha no arquivo
        line = content[lineNum].rstrip('\r\n')

        if ';' in line:
            # Ignora as linhas com ; pois sao comentarios
            line = line[:line.find(';')]

        if line != '':
            # Se a linha nao for vazia, entra no mapa
            mapTextLines.append(line)

        elif line == '' and len(mapTextLines) > 0:
            # Se houver uma linha em branco mas mais linhas foram analisadas
            # entao encerra a leitura e comeca a montagem do cenario

            # Acha a maior linha no mapa
            maxWidth = -1
            for i in range(len(mapTextLines)):
                if len(mapTextLines[i]) > maxWidth:
                    maxWidth = len(mapTextLines[i])

            # Adiciona espacos em branco no final das linhas menores
            # para garantir que os mapas sejam sempre retangulares
            for i in range(len(mapTextLines)):
                mapTextLines[i] += ' ' * (maxWidth - len(mapTextLines[i]))

            # Converte mapTextLines em uma variavel de mapa.
            for x in range(len(mapTextLines[0])):
                mapObj.append([]) # gera uma lista de listas
            for y in range(len(mapTextLines)):
                for x in range(maxWidth):
                    mapObj[x].append(mapTextLines[y][x])
                    # coloca cada elemento do textFile em uma posicao da lista

            # Itera pelo mapa procurando objetos para serem instanciados
            enemies = [] # Lista de inimigos encontrados no cenario
            itens = [] # Lista de itens encontrados no cenario
            for x in range(maxWidth):
                for y in range(len(mapObj[x])):
                    if mapObj[x][y] in ('@'):
                        # '@' eh a posicao inicial do jogador
                        PLAYER.setX(x)
                        PLAYER.setY(y)
                        mapObj[x][y] = ' '

                    if mapObj[x][y] in ('1', '2', '3', '4'):
                        # 1, 2, 3 e 4 sao inimigos
                        enemy = NPC()
                        if mapObj[x][y] == '1':
                            enemy = copy.copy(ENEMIES['1'])
                        if mapObj[x][y] == '2':
                            enemy = copy.copy(ENEMIES['2'])
                        if mapObj[x][y] == '3':
                            enemy = copy.copy(ENEMIES['3'])
                        if mapObj[x][y] == '4':
                            enemy = copy.copy(ENEMIES['4'])
                        #print("enemy:",(len(enemies)+1), " x:",x," y:",y) 
                        enemy.setX(x)
                        enemy.setY(y)
                        enemies.append(enemy)
                        mapObj[x][y] = ' '
                    
                    if mapObj[x][y] in ('a', 'b', 'c', 'd', 'e', 'f'):
                        # a, b, c, d, e e f sao itens
                        item = Item()
                        if mapObj[x][y] == 'a':
                            item = copy.copy(ITENS['a'])
                        if mapObj[x][y] == 'b':
                            item = copy.copy(ITENS['b'])
                        if mapObj[x][y] == 'c':
                            item = copy.copy(ITENS['c'])
                        if mapObj[x][y] == 'd':
                            item = copy.copy(ITENS['d'])
                        if mapObj[x][y] == 'e':
                            item = copy.copy(ITENS['e'])
                        if mapObj[x][y] == 'f':
                            item = copy.copy(ITENS['f'])
                        #print("item:",(len(itens)+1), " x:",x," y:",y) 
                        item.setX(x)
                        item.setY(y)
                        itens.append(item)
                        mapObj[x][y] = ' '

            # Cria os estados do jogo
            gameStateObj = {'player': PLAYER,
                            'enemiesamt': len(enemies)}
            levelObj = {'width': maxWidth,
                        'height': len(mapObj),
                        'mapObj': mapObj,
                        'enemies': enemies,
                        'itens': itens,
                        'startState': gameStateObj}

    return levelObj


def clearMap(mapObj):
    """Faz uma copia do mapa e remove alguns elementos para colocar
    pecas do cenario no lugar"""

    # Copia profunda do objeto, para nao alterar o original
    mapObjCopy = copy.deepcopy(mapObj)

    # Substitui os objetos posicionados por tiles
    for x in range(len(mapObjCopy)):
        for y in range(len(mapObjCopy[0])):
            if mapObjCopy[x][y] in ('@', '1', '2', '3', '4', 'a', 'b', 'c', 'd', 'e', 'f'):
                mapObjCopy[x][y] = ' '

    return mapObjCopy


def drawMap(levelObj):
    """Desenha o mapa na superficie de retorno.
    No mapa sao desenhados o personagem, inimigos, itens
    e o cenario em si."""

    mapObj = levelObj['mapObj']
    player = levelObj['startState']['player']

    # mapSurf sera a superficie onde tudo sera desenhado:
    # tiles, personagem, inimigos e itens.
    mapSurfWidth = len(mapObj) * TILEWIDTH
    mapSurfHeight = (len(mapObj[0]) - 1) * TILEHEIGHT
    mapSurf = pygame.Surface((mapSurfWidth, mapSurfHeight))
    mapSurf.fill(BGCOLOR) # start with a blank color on the surface.

    enemies = levelObj['enemies']
    itens = levelObj['itens']

    # Desenha os tiles na superficie
    for x in range(len(mapObj)):
        for y in range(len(mapObj[x])):
            spaceRect = pygame.Rect((x * TILEWIDTH, y * TILEHEIGHT, TILEWIDTH, TILEHEIGHT))
            if mapObj[x][y] in TILEMAPPING:
                baseTile = TILEMAPPING[mapObj[x][y]]

            # Primeiro desenha o cenario
            mapSurf.blit(baseTile, spaceRect)

            for item in itens:
                if item.getX() == x and item.getY() == y:
                    if item.getType() == 1:
                        mapSurf.blit(IMAGESDICT['sword'], spaceRect)
                    if item.getType() == 2:
                        mapSurf.blit(IMAGESDICT['shield'], spaceRect)
                    if item.getType() == 3:
                        mapSurf.blit(IMAGESDICT['blueshield'], spaceRect)
                    if item.getType() == 4:
                        mapSurf.blit(IMAGESDICT['armor'], spaceRect)
                    if item.getType() == 5:
                        mapSurf.blit(IMAGESDICT['yellowarmor'], spaceRect)
                    if item.getType() == 6:
                        mapSurf.blit(IMAGESDICT['accessory'], spaceRect)

            for enemy in enemies:
                if enemy.getX() == x and enemy.getY() == y:
                    if enemy.getType() == 1:
                        mapSurf.blit(IMAGESDICT['slime'], spaceRect)
                    if enemy.getType() == 2:
                        mapSurf.blit(IMAGESDICT['bat'], spaceRect)
                    if enemy.getType() == 3:
                        mapSurf.blit(IMAGESDICT['zombie'], spaceRect)
                    if enemy.getType() == 4:
                        mapSurf.blit(IMAGESDICT['skeleton'], spaceRect)
                    pygame.draw.rect(mapSurf, BLACK, (enemy.getX()*TILEWIDTH,enemy.getY()*TILEHEIGHT-15,TILEWIDTH,8), 0) # HPbar bkg
                    pygame.draw.rect(mapSurf, RED, (enemy.getX()*TILEWIDTH,enemy.getY()*TILEHEIGHT-15,(enemy.getHp()/enemy.getHpMax())*TILEWIDTH,8), 0) # HPbar frg
            
            if player.getX() == x and player.getY() == y:
                mapSurf.blit(player.getFilechar(), spaceRect)
                pygame.draw.rect(mapSurf, BLACK, (player.getX()*TILEWIDTH,player.getY()*TILEHEIGHT-15,TILEWIDTH,8), 0) # HPbar bkg
                pygame.draw.rect(mapSurf, RED, (player.getX()*TILEWIDTH,player.getY()*TILEHEIGHT-15,(player.getHp()/player.getHpMax())*TILEWIDTH,8), 0) # HPbar frg

    return mapSurf


def isWall(levelObj, x, y):
    """Retorna True se (x,y) eh uma parede."""
    mapObj = levelObj['mapObj']
    if x < 0 or x >= len(mapObj) or y < 0 or y >= len(mapObj[x]):
        return False # x e y estao fora do mapa. (sanidade mental)
    elif mapObj[x][y] in ('#', 'x'):
        return True # ha uma parede
    return False


def makeMove(levelObj, playerMoveTo):
    """Retorna True se o jogador consegue fazer o movimento, senao False.
    Eh levado em consideracao a posicao dos inimigos e itens no mapa,
    pois estes bloqueiam a rota."""

    player = levelObj['startState']['player']
    playerx = player.getX()
    playery = player.getY()

    enemies = levelObj['enemies']
    itens = levelObj['itens']


    # Gerencia o offset em x e y do jogador dependendo do
    # movimento realizado
    if playerMoveTo == UP:
        xOffset = 0
        yOffset = -1
    elif playerMoveTo == RIGHT:
        xOffset = 1
        yOffset = 0
    elif playerMoveTo == DOWN:
        xOffset = 0
        yOffset = 1
    elif playerMoveTo == LEFT:
        xOffset = -1
        yOffset = 0

    playerxM = playerx + xOffset
    playeryM = playery + yOffset

    # Verifica se o jogador pode se movimentar para aquela direcao
    if isWall(levelObj, playerx + xOffset, playery + yOffset):
        return False
    else:
        for enemy in enemies:
            if enemy.getX() == playerxM and enemy.getY() == playeryM:
                return False
        for item in itens:
            if item.getX() == playerxM and item.getY() == playeryM:
                return False

        if playerMoveTo == UP:
            player.setFilechar(IMAGESDICT['mainup'])
        elif playerMoveTo == RIGHT:
            player.setFilechar(IMAGESDICT['mainright'])
        elif playerMoveTo == DOWN:
            player.setFilechar(IMAGESDICT['maindown'])
        elif playerMoveTo == LEFT:
            player.setFilechar(IMAGESDICT['mainleft'])

        player.setOrientation(playerMoveTo)

        # Move o jogador.
        player.setX(playerxM)
        player.setY(playeryM)
        return True


def playerAttack(levelObj):
    '''Faz a verificacao da posicao de um inimigo afrente do jogador.
    Se houver um inimigo, o ataca e eh atacado pelo mesmo.
    Atualiza os atributos do personagem (HP e XP).
    retorna 0 se o jogador morre.
    retorna 1 se o jogador mata.'''

    player = levelObj['startState']['player']
    enemies = levelObj['enemies']

    if player.getOrientation() == UP:
        offsetx = 0
        offsety = -1
    elif player.getOrientation() == DOWN:
        offsetx = 0
        offsety = 1
    elif player.getOrientation() == LEFT:
        offsetx = -1
        offsety = 0
    elif player.getOrientation() == RIGHT:
        offsetx = 1
        offsety = 0

    offsetxM = player.getX() + offsetx
    offsetyM = player.getY() + offsety

    for i in range(len(enemies)):
        if enemies[i].getX() == offsetxM and enemies[i].getY() == offsetyM:
            # inimigo esta logo na frente do personagem, o ataca

            # Tira de vida:   (player.ATK + player.LVL) - (enemy.DEF + enemy.LVL)
            # Recebe de dano: (enemy.ATK + enemy.LVL) - (player.DEF + player.LVL)

            soma = lambda x, y: x + y

            dataAtaca = [PLAYER.getAttack(), PLAYER.getLevel(), -(enemies[i].getDefBase()), -(enemies[i].getLevel())]
            ataca = functools.reduce(soma, dataAtaca)

            def recebeA(a):
                def recebeB(b):
                    def recebeC(c):
                        def recebeD(d):
                            return a + b + c + d
                        return recebeD
                    return recebeC
                return recebeB
 
            recebe = recebeA(enemies[i].getAtkBase()*2)(enemies[i].getLevel())(-(PLAYER.getDefense()))(-(PLAYER.getLevel()))

            if ataca < 0: #ataque muito fraco, seta para zero
                ataca = 0

            if recebe < 0: #ataque muito fraco, seta para zero
                recebe = 0

            print("Atacou o inimigo.", ataca, "de dano.")
            print("Atacado pelo inimigo.", recebe, "de dano.")

            PLAYER.setHp(PLAYER.getHp() - recebe)
            enemies[i].setHp(enemies[i].getHp() - ataca)

            if enemies[i].getHp() <= 0: # inimigo morreu
                print(enemies[i].getName()," derrotado!")
                PLAYER.setXp(PLAYER.getXp() + enemies[i].getLevel()*2)
                print("==> XP + ", enemies[i].getLevel()*2)

                if PLAYER.getXp() >= 10: # aumentou de nivel
                    sobra = PLAYER.getXp() - 10
                    PLAYER.setLevel(PLAYER.getLevel() + 1)
                    PLAYER.setXp(sobra)
                    print("!! Aumentou de nivel !!")
                    print("Nivel: ", PLAYER.getLevel())
                    print("==> HP + 3")
                    PLAYER.setHpMax(PLAYER.getHpMax() + 3)
                    print("==> MP + 1")
                    PLAYER.setMpMax(PLAYER.getMpMax() + 1)
                    print("==> ATK + 1")
                    PLAYER.setAttack(PLAYER.getAttack() + 1)
                    print("==> DEF + 1")
                    PLAYER.setDefense(PLAYER.getDefense() + 1)
                    print("Curados HP e MP")
                    PLAYER.setHp(PLAYER.getHpMax())
                    PLAYER.setMp(PLAYER.getMpMax())

                enemies.remove(enemies[i])
                break

            if PLAYER.getHp() <= 0: # player morreu
                PLAYER.setHp(0)
                print("Quevedo morreu. Game Over!")
                return 0

            print(" ")
            return 1


def playerInteract(levelObj):
    '''Faz a verificacao da posicao de um item afrente do jogador.
    Se houver um item, o coleta e atualiza os atributos do personagem.'''
    player = levelObj['startState']['player']
    itens = levelObj['itens']

    if player.getOrientation() == UP:
        offsetx = 0
        offsety = -1
    elif player.getOrientation() == DOWN:
        offsetx = 0
        offsety = 1
    elif player.getOrientation() == LEFT:
        offsetx = -1
        offsety = 0
    elif player.getOrientation() == RIGHT:
        offsetx = 1
        offsety = 0

    offsetxM = player.getX() + offsetx
    offsetyM = player.getY() + offsety

    #print("Px:", player.getX(), " Py:", player.getY())

    for i in range(len(itens)):
        if itens[i].getX() == offsetxM and itens[i].getY() == offsetyM:
            # item esta logo na frente do personagem, o coleta
            if itens[i].getType() == 1: # uma espada
                player.setRHandItem(itens[i])
                player.setRHandEqp(True)
                player.setAttack(player.getAttack() + player.getRHandItem().getAttack())
             
                print("Adquiriu uma espada!")
                print("==> ATK +", itens[i].getAttack())
                print(" ")

                itens.remove(itens[i])
                break
            if itens[i].getType() in (2,3): # um escudo
                player.setLHandItem(itens[i])
                player.setLHandEqp(True)
                player.setDefense(player.getDefense() + player.getLHandItem().getDefense())
                
                print("Adquiriu um escudo!")
                print("==> DEF +", itens[i].getDefense())
                print(" ")

                itens.remove(itens[i])
                break
            if itens[i].getType() in (4,5): # uma armadura
                player.setArmorItem(itens[i])
                player.setArmorEqp(True)
                player.setDefense(player.getDefense() + player.getArmorItem().getDefense())
                
                print("Adquiriu uma armadura!")
                print("==> DEF +", itens[i].getDefense())
                print(" ")

                itens.remove(itens[i])
                break
            if itens[i].getType() == 6: # um acessorio
                player.setAccesorieItem(itens[i])
                player.setAccesorieEqp(True)
                player.setAttack(player.getAttack() + player.getAccesorieItem().getAttack())
                player.setDefense(player.getDefense() + player.getAccesorieItem().getDefense())
                
                print("Adquiriu um acessorio!")
                print("==> ATK +", itens[i].getAttack())
                print("==> DEF +", itens[i].getDefense())
                print(" ")

                itens.remove(itens[i])
                break
            

def runLevel(levelP):
    levelObj = levelP
    mapObj = clearMap(levelObj['mapObj'])
    gameStateObj = copy.deepcopy(levelObj['startState'])
    player = gameStateObj['player']
    enemies = levelObj['enemies']
    itens =  levelObj['itens']

    mapNeedsRedraw = True # Fica em True para forcar a chamada de drawMap()

    mapWidth = len(mapObj) * TILEWIDTH
    mapHeight = (len(mapObj[0]) - 1) * TILEHEIGHT
    MAX_CAM_X_PAN = abs(HALF_WINHEIGHT - int(mapHeight / 2)) + TILEWIDTH
    MAX_CAM_Y_PAN = abs(HALF_WINWIDTH - int(mapWidth / 2)) + TILEHEIGHT

    levelIsComplete = False
    result = 1
    gameover = False

    # Gerencia o quanto a camera se movimentou
    cameraOffsetX = MAX_CAM_Y_PAN
    cameraOffsetY = MAX_CAM_X_PAN

    # Verifica se a camera esta se movimentando
    cameraUp = False
    cameraDown = False
    cameraLeft = False
    cameraRight = False

    while True: # Laco principal do jogo
        # Reseta essas variaveis
        playerMoveTo = None
        keyPressed = False

        for event in pygame.event.get(): # itera pelos eventos
            if event.type == QUIT:
                # Jogador cliclou no "X" para fechar a janela
                terminate()

            elif event.type == KEYDOWN:
                # Manuseia o pressionar de teclas
                keyPressed = True

                if event.key == K_LEFT:
                    cameraLeft = True
                elif event.key == K_RIGHT:
                    cameraRight = True
                elif event.key == K_UP:
                    cameraUp = True
                elif event.key == K_DOWN:
                    cameraDown = True

                elif event.key == K_a:
                    playerMoveTo = LEFT
                elif event.key == K_d:
                    playerMoveTo = RIGHT
                elif event.key == K_w:
                    playerMoveTo = UP
                elif event.key == K_s:
                    playerMoveTo = DOWN

                elif event.key == K_k:
                    result = playerAttack(levelObj)
                    mapNeedsRedraw = True
                elif event.key == K_e:
                    playerInteract(levelObj)
                    mapNeedsRedraw = True

                elif event.key == K_ESCAPE:
                    terminate() # Esc key quits.
                elif event.key == K_BACKSPACE:
                    return 'reset' # Reset the level.

            elif event.type == KEYUP:
                # Desfaz a movimentacao da camera
                if event.key == K_LEFT:
                    cameraLeft = False
                elif event.key == K_RIGHT:
                    cameraRight = False
                elif event.key == K_UP:
                    cameraUp = False
                elif event.key == K_DOWN:
                    cameraDown = False

        if playerMoveTo != None:
            # Se o jogador se movimentou para alguma direcao,
            # executa o movimento testando colisao com inimigos 
            # e itens no cenario
            moved = makeMove(levelObj, playerMoveTo)

            if moved:
                #redesenha a tela
                mapNeedsRedraw = True

        if result == 0:
            # Se o jogador atacou e morreu. Game Over.
            gameOver = True

        if len(levelObj['enemies']) == 0:
            # todos os inimigos foram mortos, fim de jogo
            levelIsComplete = True
            keyPressed = False

        DISPLAYSURF.fill(BGCOLOR)

        if mapNeedsRedraw:
            mapSurf = drawMap(levelObj)
            mapNeedsRedraw = False

        if cameraUp and cameraOffsetY < MAX_CAM_X_PAN:
            cameraOffsetY += CAM_MOVE_SPEED
        elif cameraDown and cameraOffsetY > -MAX_CAM_X_PAN:
            cameraOffsetY -= CAM_MOVE_SPEED
        if cameraLeft and cameraOffsetX < MAX_CAM_Y_PAN:
            cameraOffsetX += CAM_MOVE_SPEED
        elif cameraRight and cameraOffsetX > -MAX_CAM_Y_PAN:
            cameraOffsetX -= CAM_MOVE_SPEED

        # Ajusta a superficie do mapa de acordo com a posicao da camera
        mapSurfRect = mapSurf.get_rect()
        mapSurfRect.center = (HALF_WINWIDTH + cameraOffsetX, HALF_WINHEIGHT + cameraOffsetY)

        # desenha o mapSurf no DISPLAYSURF
        DISPLAYSURF.blit(mapSurf, mapSurfRect)

        # desenha as estatisticas do personagem na tela (HP, MP, ATK e DEF)
        HPSurf = BASICFONT.render('HP: %s/%s' % (PLAYER.getHp(), PLAYER.getHpMax()), 1, RED)
        HPRect = HPSurf.get_rect()
        HPRect.topleft = (20, 35)
        DISPLAYSURF.blit(HPSurf, HPRect)

        MPSurf = BASICFONT.render('MP: %s/%s' % (PLAYER.getMp(), PLAYER.getMpMax()), 1, BLUE)
        MPRect = MPSurf.get_rect()
        MPRect.topleft = (20, 55)
        DISPLAYSURF.blit(MPSurf, MPRect)

        XPSurf = BASICFONT.render('XP: %s/10' % (PLAYER.getXp()), 1, GREEN)
        XPRect = XPSurf.get_rect()
        XPRect.topleft = (20, 75)
        DISPLAYSURF.blit(XPSurf, XPRect)

        ATKSurf = BASICFONT.render('ATK: %s' % (PLAYER.getAttack()), 1, TEXTCOLOR)
        ATKRect = ATKSurf.get_rect()
        ATKRect.topleft = (20, 95)
        DISPLAYSURF.blit(ATKSurf, ATKRect)   

        DEFSurf = BASICFONT.render('DEF: %s' % (PLAYER.getDefense()), 1, TEXTCOLOR)
        DEFRect = DEFSurf.get_rect()
        DEFRect.topleft = (20, 115)
        DISPLAYSURF.blit(DEFSurf, DEFRect)   

        if levelIsComplete:
            # Se derrotou todos os inimigos, mostra a imagem de parabenizacao.
            solvedRect = IMAGESDICT['solved'].get_rect()
            solvedRect.center = (HALF_WINWIDTH, HALF_WINHEIGHT)
            DISPLAYSURF.blit(IMAGESDICT['solved'], solvedRect)

            if keyPressed:
                return 'solved'

        if gameover:
            # Jogador foi derrotado, mostra a tela de gameover
            solvedRect = IMAGESDICT['gameover'].get_rect()
            solvedRect.center = (HALF_WINWIDTH, HALF_WINHEIGHT)
            DISPLAYSURF.blit(IMAGESDICT['gameover'], solvedRect)

            if keyPressed:
                return 'gameover'

        pygame.display.update() # desenha o DISPLAYSURF na tela
        FPSCLOCK.tick()


def terminate():
    pygame.quit()
    sys.exit()


if __name__ == '__main__':
    main()